﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Umi.Web.Abstraction.Services;
using Umi.Web.Metadatas.Attributes;
using Umi.Web.Metadatas.ServiceStruct.http;

namespace Umi.Web.Service.Services
{
    [Service]
    public class HttpService : IHttpService
    {
        private readonly HttpClient client;

        public HttpService(IHttpClientFactory factory)
        {
            client = factory.CreateClient("httpClient");
        }

        public async Task<HttpResult> Delete(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Headers.Add(item.Key, item.Value);
                    }
                }
                if (param != null)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var item in param)
                    {
                        sb.Append($"{HttpUtility.UrlEncode(item.Key)}={HttpUtility.UrlEncode(item.Value)}&");
                    }
                    sb.Remove(sb.Length - 1, 1);
                    if (url.Contains("?"))
                        url = $"{url}&{sb.ToString()}";
                    else
                        url = $"{url}?{sb.ToString()}";
                }
                message.Method = HttpMethod.Delete;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> Get(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Headers.Add(item.Key, item.Value);
                    }
                }
                if (param != null)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var item in param)
                    {
                        sb.Append($"{HttpUtility.UrlEncode(item.Key)}={HttpUtility.UrlEncode(item.Value)}&");
                    }
                    sb.Remove(sb.Length - 1, 1);
                    if (url.Contains("?"))
                        url = $"{url}&{sb.ToString()}";
                    else
                        url = $"{url}?{sb.ToString()}";
                }
                message.Method = HttpMethod.Get;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> Header(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Headers.Add(item.Key, item.Value);
                    }
                }
                if (param != null)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var item in param)
                    {
                        sb.Append($"{HttpUtility.UrlEncode(item.Key)}={HttpUtility.UrlEncode(item.Value)}&");
                    }
                    sb.Remove(sb.Length - 1, 1);
                    if (url.Contains("?"))
                        url = $"{url}&{sb.ToString()}";
                    else
                        url = $"{url}?{sb.ToString()}";
                }
                message.Method = HttpMethod.Head;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PatchForBody(string url, string body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new StringContent(body);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }

                message.Method = new HttpMethod("PATCH");
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PatchForForm(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new FormUrlEncodedContent(param);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = new HttpMethod("PATCH");
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PatchForMutiPart(string url, IDictionary<string, string> param, IDictionary<string, Stream> files, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                MultipartFormDataContent content = new MultipartFormDataContent();
                if (param != null)
                {
                    foreach (var item in param)
                    {
                        content.Add(new StringContent(item.Value), item.Key);
                    }
                }
                if (files != null)
                {
                    foreach (var item in files)
                    {
                        content.Add(new StreamContent(item.Value), item.Key);
                    }
                }
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = new HttpMethod("PATCH");
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PatchForStream(string url, Stream body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                StreamContent content = new StreamContent(body);
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = new HttpMethod("PATCH");
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PostForBody(string url, string body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new StringContent(body);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }

                message.Method = HttpMethod.Post;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PostForForm(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new FormUrlEncodedContent(param);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Post;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PostForMutiPart(string url, IDictionary<string, string> param, IDictionary<string, Stream> files, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                MultipartFormDataContent content = new MultipartFormDataContent();
                if (param != null)
                {
                    foreach (var item in param)
                    {
                        content.Add(new StringContent(item.Value), item.Key);
                    }
                }
                if (files != null)
                {
                    foreach (var item in files)
                    {
                        content.Add(new StreamContent(item.Value), item.Key);
                    }
                }
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Post;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PostForStream(string url, Stream body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                StreamContent content = new StreamContent(body);
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Post;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PutForBody(string url, string body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new StringContent(body);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }

                message.Method = HttpMethod.Put;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PutForForm(string url, IDictionary<string, string> param, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                message.Content = new FormUrlEncodedContent(param);
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        message.Content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Put;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PutForMutiPart(string url, IDictionary<string, string> param, IDictionary<string, Stream> files, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                MultipartFormDataContent content = new MultipartFormDataContent();
                if (param != null)
                {
                    foreach (var item in param)
                    {
                        content.Add(new StringContent(item.Value), item.Key);
                    }
                }
                if (files != null)
                {
                    foreach (var item in files)
                    {
                        content.Add(new StreamContent(item.Value), item.Key);
                    }
                }
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Put;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }

        public async Task<HttpResult> PutForStream(string url, Stream body, IDictionary<string, string> header)
        {
            if (string.IsNullOrEmpty(url))
                throw new ArgumentNullException(nameof(url));
            using (HttpRequestMessage message = new HttpRequestMessage())
            {
                StreamContent content = new StreamContent(body);
                message.Content = content;
                if (header != null)
                {
                    foreach (var item in header)
                    {
                        content.Headers.Add(item.Key, item.Value);
                    }
                }
                message.Method = HttpMethod.Put;
                message.RequestUri = new Uri(url);
                HttpResponseMessage response = await client.SendAsync(message);
                return new HttpResult(response, await response.Content.ReadAsStreamAsync());
            }
        }
    }
}
